package com.hhkj.payment.wechat.notification.common.handler;

import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.hhkj.payment.wechat.common.component.provider.ConfProvider;
import com.hhkj.payment.wechat.notification.common.cont.ProcessorEnum;
import com.hhkj.payment.wechat.notification.common.parser.Parser;
import com.hhkj.payment.wechat.notification.common.processor.Processor;
import com.hhkj.payment.wechat.notification.domain.NotificationHandLog;
import com.hhkj.payment.wechat.notification.service.base.NotificationHandLogService;
import com.ruoyi.common.exception.GlobalException;
import com.wechat.pay.java.core.notification.Notification;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.RequestParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * NotificationHandler
 *
 * @author HHKJ-SERVER-ZJ
 * @since 2023/11/22 19:29
 */
@Slf4j
@Component
public class NotificationHandler {

    @Autowired
    private NotificationHandLogService handLogService;

    /**
     * 处理请求参数
     *
     * @param request http请求信息
     */
    public void hand(HttpServletRequest request) {
        RequestParam requestParam = getRequestParamFromRequest(request);
        // 初始化 NotificationParser
        Parser notificationParser
                = new Parser((NotificationConfig) ConfProvider.getRSAAutoCertificateConfig());
        // 获取消息通知实体信息
        Notification notification
                = notificationParser.getNotificationFromRequestParam(requestParam);
        log.info(notification.toString());
        String eventType = notification.getEventType();
        ProcessorEnum processorEnum = ProcessorEnum.getByEventTypeCode(eventType);
        boolean handedFlag = false;
        Object decryptObj = null;
        if (processorEnum != null) {
            // springboot容器中根据接口获取接口实现类bean集合
            Map<String, ?> processorBeanMap =
                    SpringUtil.getBeansOfType(processorEnum.getClazz());
            if (processorBeanMap != null && !processorBeanMap.isEmpty()) {
                Object processorBeanObj;
                Processor processorBean;
                handedFlag = true;
                // 后置处理
                for (Map.Entry<String, ?> processorBeanMapEntry : processorBeanMap.entrySet()) {
                    // 调用bean的process方法，无须指定业务处理类
                    processorBeanObj = processorBeanMapEntry.getValue();
                    if (processorBeanObj instanceof Processor) {
                        processorBean = (Processor) processorBeanObj;
                        decryptObj = processorBean.process(notification, notificationParser);
                    }
                }
            } else {
                log.warn("无对应处理业务");
            }
        } else {
            log.warn("没有对应处理器");
        }
        // 处理日志记录
        NotificationHandLog notificationHandLogDo
                = new NotificationHandLog(eventType, notification.toString(), (handedFlag ? 1 : 0), String.valueOf(decryptObj));
        handLogService.save(notificationHandLogDo);
        if (!handedFlag) {
            throw new GlobalException("处理失败");
        }
    }

    /**
     * 从请求中获取参数信息
     *
     * @param request 请求信息
     * @return 参数信息
     */
    private RequestParam getRequestParamFromRequest(HttpServletRequest request) {
        //从请求头获取验签字段
        String wechatTimestamp = request.getHeader("Wechatpay-Timestamp");
        String wechatPayNonce = request.getHeader("Wechatpay-Nonce");
        String wechatSignature = request.getHeader("Wechatpay-Signature");
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");

        String requestBody = ServletUtil.getBody(request);

        // 构造 RequestParam
        return new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(wechatPayNonce)
                .signature(wechatSignature)
                .timestamp(wechatTimestamp)
                .body(requestBody)
                .build();
    }
}
